﻿package {


	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import flash.net.URLVariables;
	
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.HTTPStatusEvent;
	
	import com.glidecast.common.gcSettings;
	
	import com.glidecast.models.Segment;
	import com.glidecast.models.Content;
	import com.glidecast.models.Template;
	import com.glidecast.models.Audio;
	import com.glidecast.models.Graphic;


	import com.glidecast.controllers.ContentController;
	import com.glidecast.controllers.TemplateController;	
	
	public class GlideCastController {
		private var _model:GlideCastModel;
		
		private var _segmentCounter:int=0;
		private var _segmentMaximumCount:int=0;
		
		private var _contentCounter:int=0;
		private var _contentMaximumCount:int=0;		

		//TODO: I do not know how to resolve the issue of RSSItems at the content or segment level.
		//either way, they will load asynch, so we don't know initially how many there are.
		
		//crossing a content boundary when merging with the template is a problem. So you would
		// not have content A for position 1 and 2 and content B for position 3. You'd only have 
		// position 1 and 2.
		private var _itemCounter:int=0;
		private var _itemMaximumCount:int=0;		
		
		private var _loader:URLLoader=new URLLoader;
		private var _loaderThumb:URLLoader=new URLLoader;
		private var _segment_timer:Timer = new Timer(3000);
		private var _cycle_timer:Timer = new Timer(3000);
		
		public function GlideCastController(m:GlideCastModel)
		{
			_model=m;
			_loader.addEventListener(Event.COMPLETE,completeHandler);
			_loaderThumb.addEventListener(HTTPStatusEvent.HTTP_STATUS, loadThumbStatusHandler);
		}
		public function load(gcid:String):void
		{
			try
			{
				_segment_timer.addEventListener("timer", segmenttimerHandler);
				_segment_timer.start();
				
				_cycle_timer.addEventListener("timer", cycletimerHandler);
				_cycle_timer.start();
				
				//use the id to build a URL, then request it
				var request:URLRequest=new URLRequest(gcSettings.gcGDFUrl(gcid));
				//use a loader to init download
				_loader.load(request);
				
				trace("getting: " + gcSettings.gcGDFThumbUrl(gcid));
				//use the id to build a thumb URL, then request it
				var requestThumb:URLRequest=new URLRequest(gcSettings.gcGDFThumbUrl(gcid));
				//use a loader to init download
				_loaderThumb.load(requestThumb);
			}
			catch (error:Error)
			{
				trace("Error during load: "+error);
			}
		}
		private function completeHandler(event:Event):void
		{
			try
			{
				//get the gdf xml from the response
				var loader:URLLoader = URLLoader(event.target);
				
				trace("Loading main xml");
				//convert to an xml object
				var gdfXML:XML = XML(loader.data);

				trace("Loaded main xml");				
				
				//prime the model's segments
				var sgArray:Array = new Array();
							
				for each (var vSegment:XML in gdfXML.segments.segment)
				{
					//for each segment, create a segment object
					var tvSegment:Segment = new Segment();
					
					//populate its members
					tvSegment.name = vSegment.name;
					tvSegment.duration = vSegment.duration;
					
					var tvTemplate:Template = new Template();
					tvTemplate.url = vSegment.template.@url;
					// need to load template
					
					var tvTemplateController:TemplateController = new TemplateController();
					tvTemplateController.template = tvTemplate;
					tvTemplateController.load();
					
					tvSegment.template = tvTemplate;
					
					var tvAudio:Audio = new Audio();
					tvAudio.url = vSegment.audio.@url;
					tvAudio.volume = Math.min(vSegment.audio.@volume/100, 1);
					tvAudio.effect = vSegment.audio.@effect;
					tvAudio.load();//TODO: controller
					tvSegment.audio = tvAudio;
					
					var tvGraphic:Graphic = new Graphic();
					tvGraphic.url = vSegment.graphic.@url;
					tvGraphic.effect = vSegment.graphic.@effect;
					tvGraphic.animation = vSegment.graphic.@animation;
					tvGraphic.load();//TODO: controller			
					tvSegment.graphic = tvGraphic;
					
					//prime the segment's content
					var ctArray:Array = new Array();

					for each (var vContentItem:XML in vSegment.contentItems.content)
					{
						var tvContent:Content = new Content();
						tvContent.type = vContentItem.@type;
						tvContent.url = vContentItem.@url;
						tvContent.cycletime = vContentItem.@cycletime;
						tvContent.rawtext = vContentItem.content;
						
						var tvContentController:ContentController = new ContentController();
						tvContentController.content = tvContent;
						tvContentController.load();
						
						ctArray.push(tvContent);
						trace("adding content to array");
					}
					
					//add the content items to the segment
					tvSegment.contents = ctArray;
					
					sgArray.push(tvSegment);					
					
				}
				
				//then add it to the model array.
				_model.segments = sgArray;
				
				//The model is now primed and ready for action.
				//initialize the segment counter and maximum
				
				_segmentCounter= -1;
				_segmentMaximumCount=_model.segments.length;
				trace("finished loading.");
				
				nextSegment();
			}
			catch(error:Error)
			{
				trace("Error parsing gdf XML: "+error);
			}
		}
		private function loadThumbStatusHandler(event:HTTPStatusEvent):void
		{
			try
			{
				if (event.status == 404)
				{
					_model.needThumb = true;
				}
			}
			catch(error:Error)
			{
				trace("Error dealing with thumb status: "+error);
			}
		}
		private function nextSegment():void
		{
			try
			{
				// Increment the segment counter
				_segmentCounter++;
				if (_segmentCounter>(_segmentMaximumCount-1))
					_segmentCounter=0;
					
				trace("seg counter" + _segmentCounter.toString());
				
				var curSegment:Segment = _model.segments[_segmentCounter];				
				_contentCounter= -1;
				_contentMaximumCount = curSegment.contents.length;
				_itemCounter=0;
				_itemMaximumCount=0;
				
				var tvDate:Date = new Date();

				// If the current Segment has never downloaded anything, gets its audio and graphics.
				// these items are a one-time download.
				if (curSegment.lastModified==null)
				{
					//download binaries once.
					if (curSegment.audio !=null)	
						curSegment.audio.load();
						
					if (curSegment.graphic != null)
						curSegment.graphic.load();
						
					curSegment.lastModified = new Date();
				}
				
				//as the graphic is required to change, it should change
				_model.graphic = curSegment.graphic;
				
				//audio is a problem. Only if the audio is different
				//should it be changed.
				if (_model.audio.url != curSegment.audio.url)
				{
					_model.audio = curSegment.audio;					
				}
				
				// Adjust the segment interval to correspond to the current 
				// Segment's duration
				_segment_timer.stop();
				_segment_timer = new Timer(Number(curSegment.duration));
				_segment_timer.addEventListener("timer", segmenttimerHandler);
				_segment_timer.start();
				
				nextCycle();
			}
			catch(error:Error)
			{
				trace("nextSegment error: "+error);
				trace("seg counter" + _segmentCounter.toString());
				trace(error.getStackTrace());
			}

		}
		/*
			The next cycle function presents the next template.maxitems (e.g. 3)
			from the segment's total list of content items.
			
			These content items are the complete list of all RSSItems from all
			content sources.
		*/
		private function nextCycle():void
		{
			try
			{
				var curSegment:Segment = _model.segments[_segmentCounter];
				
				// Increment the RSSItem counter by the number of items previously
				// displayed by the template
				_itemCounter+=curSegment.template.maxitems;
				
				if (_itemCounter>(_itemMaximumCount-1))
				{
					_contentCounter++;
					if (_contentCounter>(_contentMaximumCount-1))
						_contentCounter=0;
					
					_itemCounter=0;
					_itemMaximumCount=curSegment.contents[_contentCounter].RSSItems.length;
				}
				trace("counter: " + _itemCounter + ", maxcount: " + _itemMaximumCount + ", maxitems: " + curSegment.template.maxitems);
				
				
				var curContent:Content = curSegment.contents[_contentCounter];
				//need to increment the cycle count within the current segment's content.
				//if this is RSS, its easy.
				
				//Content needs to be updated periodically (say every 15 minutes). As such,
				//this if block controls that update.	
				var tvDate:Date = new Date();	
				// DEFECT: Only one content item will be updated if the interval is triggered.		
				if (curSegment.lastModified.getTime() < (tvDate.getTime()- gcSettings.FEED_INTERVAL))
				{	
					if (curContent!=null)
					{
						var tvContentController:ContentController = new ContentController();
						tvContentController.content = curContent;
						tvContentController.load();
					}
					curSegment.lastModified = new Date();
				}
					
				// contruct the text that will populate the model.
				var itemArray:Array = new Array();
				for (var i:int=_itemCounter;i<(_itemCounter+curSegment.template.maxitems);i++)
				{
					if (i<_itemMaximumCount)
					{
						itemArray.push(curContent.RSSItems[i].title);
						itemArray.push(curContent.RSSItems[i].description);
						itemArray.push(curContent.RSSItems[i].enclosureurl);
					}
				}
				
				var tvTempController:TemplateController = new TemplateController();
				tvTempController.template = curSegment.template;
				_model.templatetype = curSegment.template.type;
				_model.style = curSegment.template.styledefinition;				
				_model.text = tvTempController.mergeTemplate(curContent.title, itemArray, "");
								
				trace("cycle counter" + _contentCounter.toString());
				
				// Need to adjust the cycle timer
				_cycle_timer.stop();
				_cycle_timer = new Timer(Number(curContent.cycletime)+gcSettings.TRANSITION_INTERVAL);
				_cycle_timer.addEventListener("timer", cycletimerHandler);
				_cycle_timer.start();
			}
			catch(error:Error)
			{
				trace("nextCycle error: "+error);
				trace(error.getStackTrace());
			}
		}
		
		public function segmenttimerHandler(event:TimerEvent):void
		{
			try
			{
				nextSegment();
			}
			catch(error:Error)
			{
				trace("Error during timerHandler: " +error);
			}			
		}
		/*
			steps to the next cycle in the segment's content.
		*/
		public function cycletimerHandler(event:TimerEvent):void
		{
			try
			{
				nextCycle();
			}
			catch(error:Error)
			{
				trace("Error during timerHandler: " +error);
			}			
		}
		public function pause():void
		{
			_model.isPaused = true;
			_cycle_timer.stop();
			_segment_timer.stop();
			_model.audio.pause();
		}
		public function resume():void
		{
			_model.isPaused = false;
			_cycle_timer.start();
			_segment_timer.start();
			_model.audio.resume();
		}
		
	}
}
